/*
 * Copyright 2023 devaper
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.github.devaper.pigeon.handler.argument

import io.github.devaper.pigeon.handler.method.*
import io.github.devaper.pigeon.request.*
import java.lang.reflect.*

/**
 * 需要以单个键多个值形式添加到请求模板的参数处理器基本实现
 *
 * 例如请求头、请求参数
 */
abstract class AbstractMultiValueArgumentHandler : ArgumentHandler {

    override fun handle(
        methodHandler: AbstractHttpMethodHandler,
        parameterIndex: Int,
        arguments: Array<out Any?>,
        requestTemplate: RequestTemplate
    ) {
        val value = arguments[parameterIndex] ?: return

        if (value is Map<*, *>) {
            value.forEach { (name, value) ->
                if (value is Collection<*>) {
                    value.forEach { addValue(requestTemplate, name.toString(), it.toString()) }
                } else {
                    addValue(requestTemplate, name.toString(), value.toString())
                }
            }
        } else {
            val name = determineName(methodHandler, parameterIndex)
            if (value is Collection<*>) {
                value.forEach { addValue(requestTemplate, name, it.toString()) }
            } else if (value::class.java.isArray) {
                (value as Array<*>).forEach { addValue(requestTemplate, name, it.toString()) }
            } else {
                addValue(requestTemplate, name, value.toString())
            }
        }
    }

    /**
     * 决定当前键的名称
     *
     * @param methodHandler [AbstractHttpMethodHandler]
     * @param parameterIndex 当前参数索引, 结合前面的methodHandler取出具体 [Parameter]
     * @return 键名称, 调用 [addValue] 时 name 就是这个名称
     */
    abstract fun determineName(methodHandler: AbstractHttpMethodHandler, parameterIndex: Int): String

    /**
     * 添加键值到请求模板, 一个键多次添加应该形成集合而不是覆盖原先的值
     *
     * @param requestTemplate 请求模板
     * @param name 键
     * @param value 值
     */
    abstract fun addValue(requestTemplate: RequestTemplate, name: String, value: String)
}